from Base import *
from Header import *

class CFuncStaInfo(object):
    _gStaNameDict={2:"Enabled", 3:"Disabled", 0x82:"Failed to enable", 0x83:"Failed to disable"}
    _gFunction = CONTROL_FUNCTION_NONE

    def __init__(self):
        self._successor=0

    def SetSuccessor(self, successor):
        self._successor=successor

    def AddInfoImp(self, funcStaEle):
        item = funcStaEle._subList[funcStaEle._gNameFuncSta]
        sta = funcStaEle._sta
        if sta in self._gStaNameDict:
            item._infoStr = self._gStaNameDict[funcStaEle._sta]
        else:
            item._errStr = "Invalid Status"


    def AddInfo(self, funcStaEle):
        if funcStaEle._function == self._gFunction:
            self.AddInfoImp(funcStaEle)
        else:
            if self._successor != 0:
                self._successor.AddInfo(funcStaEle)

class CFuncStaInfoMil(CFuncStaInfo):
    _gFunction = CONTROL_FUNCTION_MIL

class CFuncStaInfoMan(CFuncStaInfo):
    _gFunction = CONTROL_FUNCTION_MAN

class CFuncStaInfoAlm(CFuncStaInfo):
    _gFunction = CONTROL_FUNCTION_ALM

class CFuncStaInfoSvt(CFuncStaInfo):
    _gStaNameDict={2:"Started", 3:"Stopped", 0x82:"Failed to start", 0x83:"Failed to stop"}
    _gFunction = CONTROL_FUNCTION_SVT


class CFuncStaInfoRdc(CFuncStaInfo):
    _gStaNameDict={2:"Locked", 3:"UnLocked", 0x82:"Failed to lock", 0x83:"Failed to unlock"}
    _gFunction = CONTROL_FUNCTION_RDC
    _gMaskFlDoor = 0x80
    _gMaskFrDoor = 0x40
    _gMaskRlDoor = 0x20
    _gMaskRrDoor = 0x10
    _gMaskBackDoor = 0x08
    _gMaskTrunkDoor = 0x04
    _gMaskReserved = 0x03

    def CreateDoorStatus(self, name, mask, item):
        subItem = item.CreateSubItem(name)
        if self._doorStatus & mask == mask:
            subItem._rawStr = "1"
            subItem._infoStr = "Open"
        else:
            subItem._rawStr = "0"
            subItem._infoStr = "Close"

    def AddInfoImp(self, funcStaEle):
        super(CFuncStaInfoRdc, self).AddInfoImp(funcStaEle)

        item = funcStaEle._subList[funcStaEle._gNamePara]
        para = funcStaEle._para
        if len(para) != 1:
            item._errStr = "Invalid para"
        else:
            self._doorStatus = para[0]
            self.CreateDoorStatus("Front Left Door", self._gMaskFlDoor,item)
            self.CreateDoorStatus("Front Right Door", self._gMaskFrDoor,item)
            self.CreateDoorStatus("Rear Left Door", self._gMaskRlDoor,item)
            self.CreateDoorStatus("Rear Right Door", self._gMaskRrDoor,item)
            self.CreateDoorStatus("Back Door", self._gMaskBackDoor,item)
            self.CreateDoorStatus("Trunk Door", self._gMaskTrunkDoor,item)

class CFuncStaInfoSpd(CFuncStaInfo):
    _gStaNameDict={3:"Cancelled", 0x83:"Failed to disable"}
    _gFunction = CONTROL_FUNCTION_SPD
    _gMaskSpdId = 0x0F

    def AddInfoImp(self, funcStaEle):
        super(CFuncStaInfoSpd, self).AddInfoImp(funcStaEle)

        item = funcStaEle._subList[funcStaEle._gNamePara]
        para = funcStaEle._para
        if len(para) != 1:
            item._errStr = "Invalid para"
        else:
            temp = para[0]
            id = temp & self._gMaskSpdId
            if id < 3:
                item._infoStr = "Id is <" + DATA_FORMAT.format(id) + ">"
            else:
                item._errStr = "Invalid id <" + DATA_FORMAT.format(id) + ">"

class CFuncStaInfoGeo(CFuncStaInfo):
    _gStaNameDict={3:"Cancelled", 0x83:"Failed to cancel"}
    _gFunction = CONTROL_FUNCTION_GEO
    _gMaskGeoId = 0x0F
    _gMaskGeoType = 0xF0
    _gTypeDict={0:"Inclusion", 1:"Exclusion"}

    def AddInfoImp(self, funcStaEle):
        super(CFuncStaInfoGeo, self).AddInfoImp(funcStaEle)

        item = funcStaEle._subList[funcStaEle._gNamePara]
        para = funcStaEle._para
        if len(para) != 1:
            item._errStr = "Invalid para"
        else:
            temp = para[0]
            subItem = item.CreateSubItem("Geo-Fence Type")
            type = temp & self._gMaskGeoType
            subItem._rawStr = DATA_FORMAT.format(type)
            if type in self._gTypeDict:
                subItem._infoStr = self._gTypeDict[type]
            else:
                subItem._errStr = "Invalid Type"

            subItem = item.CreateSubItem("Geo-Fence ID")
            id = temp & self._gMaskGeoId
            subItem._rawStr = DATA_FORMAT.format(id)
            if id > 14:
                subItem._errStr = "Invalid ID <" + DATA_FORMAT.format(id) + ">"






#this function is responsibile to set chain well to avoid bad loop
def AddFuncStaResponseChain(fn):
    def new(self,*args):
        fsDefault = CFuncStaInfo()

        fsSvt = CFuncStaInfoSvt()
        fsSvt.SetSuccessor(fsDefault)

        fsRdc = CFuncStaInfoRdc()
        fsRdc.SetSuccessor(fsSvt)

        fsSpd = CFuncStaInfoSpd()
        fsSpd.SetSuccessor(fsRdc)

        fsGeo = CFuncStaInfoGeo()
        fsGeo.SetSuccessor(fsSpd)

        fsMil = CFuncStaInfoMil()
        fsMil.SetSuccessor(fsGeo)

        fsMan = CFuncStaInfoMan()
        fsMan.SetSuccessor(fsMil)

        fsAlm = CFuncStaInfoAlm()
        fsAlm.SetSuccessor(fsMan)

        return fn(self, successor=fsAlm)
    return new

class CFunctionStatusElement(CInfoElement):
    _gName = "Function Status Element"
    _gNameFuncSta = "Function Status"
    _gNameSubHd = "Sub Head"
    _gNamePara = "Parameter"

    _gHeaderLen = 3

    @AddFuncStaResponseChain
    def __init__(self, name=_gName, successor=0):
        super(CFunctionStatusElement, self).__init__(name)
        self._sta = -1
        #parameter may have more than 1 byte
        self._para= []

        #sta information is different depend on control function
        self._function=0

        #this is response chain, it's used to add different informantion
        #depend on different control function type
        self._successor = successor
        self._hlColor = 'white_on_blue'

    def SetFunction(self, function):
        self._function = function

    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name, recommendedLen=self._gHeaderLen)
        self._subList[name] = item
        self._nameList.append(name)

        self.CreateSubItem(self._gNameFuncSta)

        #self.CreateHeader(self._gNameSubHd)  #paramter has a element header format, which indicates lengths of parameter2
        name = self._gNameSubHd
        item = CEleHeader(name)
        self._subList[name] = item
        self._nameList.append(name)

        self.CreateSubItem(self._gNamePara)

    def ParseElement(self, dataStr):
        self._sta = dataStr.GetByte()
        item = self._subList[self._gNameFuncSta]
        item._rawStr = HEX_DATA_FORMAT.format(self._sta)

        #parameter is in format of element header
        subHd = self._subList[self._gNameSubHd]
        subHd.Parse(dataStr)

        item = self._subList[self._gNamePara]
        startIx = dataStr.GetIndex()
        len = subHd.GetLength()
        for i in range(0, len):
            byte = dataStr.GetByte()
            self._para.append(byte)
        paraStr = dataStr.GetString(startIx, startIx+len)
        item._rawStr = DATA_STRING_FORMAT.format(paraStr)


        if self._successor != 0:
            self._successor.AddInfo(self)

        return


